package org.scohen.juploadr.app.geo;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.scohen.juploadr.upload.HttpClientFactory;
import org.scohen.juploadr.util.HttpUtils;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
public class YahooGeoCoder implements GeoCoder {
    private String appID = "kccdOn_V34HcdnE1Q4JyEeo4EpFsZUNs2QJgMn_0AZWcisjVVBizU9DJfCXXNtTxG.g5";
    private static List<String> precisions = new ArrayList<String>();
    static {
        precisions.add("none"); //gets rid of zero-based index
        precisions.add("world");
        precisions.add("country");
        precisions.add("state");
        precisions.add("city");
        precisions.add("zip");
        precisions.add("zip+2");
        precisions.add("zip+4");
        precisions.add("street");
        precisions.add("address");

    }

    public GeoLocation geoCode(String name, String location) {
        HttpClient client = HttpClientFactory.getHttpClient();
        GetMethod get = new GetMethod("http://local.yahooapis.com/MapsService/V1/geocode");
        Map<String, String> params = new HashMap<String, String>();
        params.put("appid", appID);
        params.put("location", location);
        get.setQueryString(HttpUtils.mapToQueryString(params));
        GeoLocation loc = null;

        try {
            int responseCode = client.executeMethod(get);
            if (responseCode == 200) {
                loc = parseResponse(get.getResponseBodyAsString());
            }
        } catch (HttpException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return loc;
    }

    private GeoLocation parseResponse(String response) {
        GeoLocation loc = null;
        System.setProperty("org.xml.sax.driver", //$NON-NLS-1$
                "com.bluecast.xml.Piccolo"); //$NON-NLS-1$

        try {
            XMLReader reader = XMLReaderFactory.createXMLReader();
            ContentHandler h = new DefaultHandler() {

            };
            YahooGeoCodeResponseHandler handler = new YahooGeoCodeResponseHandler();
            reader.setContentHandler(handler);
            reader.parse(new InputSource(new StringReader(response)));
            loc = new GeoLocation();
            loc.setAccuracy(precisions.indexOf(handler.getPrecision()) * 2);
            loc.setLatitude(handler.getLatitude());
            loc.setLongitude(handler.getLongitude());

        } catch (SAXException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return loc;
    }

    public GeoLocation geoCode(String name, String city, String state, String postalCode) {
        // TODO Auto-generated method stub
        return null;
    }

    private class YahooGeoCodeResponseHandler extends DefaultHandler {
        private double latitude;
        private double longitude;
        private String precision;
        private String lastTag;

        @Override
        public void startElement(String uri, String localName, String qname, Attributes atts) throws SAXException {
            lastTag = qname;
            if (lastTag.equalsIgnoreCase("Result")) {
                precision = atts.getValue("precision");
            }
        }

        @Override
        public void characters(char[] characters, int start, int end) throws SAXException {
            String s = new String(characters, start, end);
            if (s.length() > 0) {
                if (lastTag.equalsIgnoreCase("Latitude")) {

                    latitude = Double.valueOf(new String(characters, start, end));
                } else if (lastTag.equalsIgnoreCase("Longitude")) {
                    longitude = Double.valueOf(new String(characters, start, end));
                }
            }
        }

        public double getLatitude() {
            return latitude;
        }

        public double getLongitude() {
            return longitude;
        }

        public String getPrecision() {
            return precision;
        }

    }
}
